package com.yinsin.other;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

public class LogHelper {
	private static SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss.SSS");
    private Object logObj = null;

    private LogHelper() {

    }

    public static LogHelper getLogger(Class<?> clas) {
        LogHelper log = new LogHelper();
        Object logObj = getLoggerBean(clas, "org.slf4j.LoggerFactory");
        if (logObj != null) {
            log.logObj = logObj;
        } else {
        	logObj = getLoggerBean(clas, "org.apache.log4j.Logger");
        	if (logObj != null) {
                log.logObj = logObj;
            }
        }
        return log;
    }

    private String getLogInfo(String level, String fix, String msg) {
        StringBuilder sb = new StringBuilder();
        sb.append("[YsDevKit] ")
            .append(format.format(new Date()))
            .append(" ")
            .append(level)
            .append(" ")
            .append(fix)
            .append("：")
            .append(msg);
        return sb.toString();
    }

    public void debug(String msg) {
        if (logObj != null) {
            callBeanMethod(logObj, "debug", new Object[]{ msg });
        } else {
            StackTraceElement[] temp = Thread.currentThread().getStackTrace();
            StackTraceElement stack = (StackTraceElement) temp[2];
            String logFix = getLogClassMethod(stack);
            System.out.println(getLogInfo("DEBUG", logFix, msg));
        }
    }
    
    public void debug(String format, Object... args) {
        if (logObj != null) {
            callBeanMethod(logObj, "debug", args);
        } else {
        	debug(String.format(format, args));
        }
    }

    public void debug(String msg, Exception e) {
        if (logObj != null) {
            callBeanMethod(logObj, "debug", new Object[]{ msg , e});
        } else {
            StackTraceElement[] temp = Thread.currentThread().getStackTrace();
            StackTraceElement stack = (StackTraceElement) temp[2];
            String logFix = getLogClassMethod(stack);
            System.out.println(getLogInfo("DEBUG", logFix, msg));
            e.printStackTrace();
        }
    }

    public void info(String msg) {
        if (logObj != null) {
            callBeanMethod(logObj, "info", new Object[]{ msg });
        } else {
            StackTraceElement[] temp = Thread.currentThread().getStackTrace();
            StackTraceElement stack = (StackTraceElement) temp[2];
            String logFix = getLogClassMethod(stack);
            System.out.println(getLogInfo("INFO", logFix, msg));
        }
    }
    
    public void info(String format, Object... args) {
        if (logObj != null) {
            callBeanMethod(logObj, "info", args);
        } else {
            info(String.format(format, args));
        }
    }

    public void info(String msg, Exception e) {
        if (logObj != null) {
            callBeanMethod(logObj, "info", new Object[]{ msg, e });
        } else {
            StackTraceElement[] temp = Thread.currentThread().getStackTrace();
            StackTraceElement stack = (StackTraceElement) temp[2];
            String logFix = getLogClassMethod(stack);
            System.out.println(getLogInfo("INFO", logFix, msg));
            e.printStackTrace();
        }
    }

    public void error(String msg) {
        if (logObj != null) {
            callBeanMethod(logObj, "error", new Object[]{ msg });
        } else {
            StackTraceElement[] temp = Thread.currentThread().getStackTrace();
            StackTraceElement stack = (StackTraceElement) temp[2];
            String logFix = getLogClassMethod(stack);
            System.err.println(getLogInfo("ERROR", logFix, msg));
        }
    }
    
    public void error(String format, Object... args) {
    	if (logObj != null) {
    		callBeanMethod(logObj, "error", args);
    	} else {
    		error(String.format(format, args));
    	}
    }

    public void error(String msg, Exception e) {
        if (logObj != null) {
            callBeanMethod(logObj, "error", new Object[]{ msg, e });
        } else {
            StackTraceElement[] temp = Thread.currentThread().getStackTrace();
            StackTraceElement stack = (StackTraceElement) temp[2];
            String logFix = getLogClassMethod(stack);
            System.err.println(getLogInfo("ERROR", logFix, msg));
            e.printStackTrace();
        }
    }

    public void waring(String msg) {
        if (logObj != null) {
            callBeanMethod(logObj, "waring", new Object[]{ msg });
        } else {
            StackTraceElement[] temp = Thread.currentThread().getStackTrace();
            StackTraceElement stack = (StackTraceElement) temp[2];
            String logFix = getLogClassMethod(stack);
            System.err.println(getLogInfo("WARING", logFix, msg));
        }
    }
    
    public void waring(String format, Object... args) {
        if (logObj != null) {
            callBeanMethod(logObj, "waring", args);
        } else {
        	waring(String.format(format, args));
        }
    }

    public void waring(String msg, Exception e) {
        if (logObj != null) {
            callBeanMethod(logObj, "waring", new Object[]{ msg, e });
        } else {
            StackTraceElement[] temp = Thread.currentThread().getStackTrace();
            StackTraceElement stack = (StackTraceElement) temp[2];
            String logFix = getLogClassMethod(stack);
            System.err.println(getLogInfo("WARING", logFix, msg));
            e.printStackTrace();
        }
    }

    public void fatch(String msg) {
        if (logObj != null) {
            callBeanMethod(logObj, "fatch", new Object[]{ msg });
        } else {
            StackTraceElement[] temp = Thread.currentThread().getStackTrace();
            StackTraceElement stack = (StackTraceElement) temp[2];
            String logFix = getLogClassMethod(stack);
            System.err.println(getLogInfo("FATCH", logFix, msg));
        }
    }
    
    public void fatch(String format, Object... args) {
        if (logObj != null) {
            callBeanMethod(logObj, "fatch", args);
        } else {
        	fatch(String.format(format, args));
        }
    }

    public void fatch(String msg, Exception e) {
        if (logObj != null) {
            callBeanMethod(logObj, "fatch", new Object[]{ msg, e });
        } else {
            StackTraceElement[] temp = Thread.currentThread().getStackTrace();
            StackTraceElement stack = (StackTraceElement) temp[2];
            String logFix = getLogClassMethod(stack);
            System.err.println(getLogInfo("FATCH", logFix, msg));
            e.printStackTrace();
        }
    }

    private String getLogClassMethod(StackTraceElement stack) {
        StringBuilder sb = new StringBuilder();
        sb.append("[")
            .append(stack.getClassName())
            .append("：")
            .append(stack.getLineNumber())
            .append("]")
            .append("[")
            .append(stack.getMethodName())
            .append("]");
        return sb.toString();
    }
    
    @SuppressWarnings("unchecked")
    private static <T> T getLoggerBean(Class<?> clasz, String classPath) {
        T t = null;
        try {
            Class<T> aClass = (Class<T>) Class.forName(classPath);
            Method method = aClass.getMethod("getLogger", new Class[]{ Class.class });
            t = (T) method.invoke(null, new Object[] { clasz });
        } catch (Exception e) {
            t = null;
        }
        return t;
    }
    
    private static <T> Object callBeanMethod(T t, String methodName, Object[] param) {
		Object result = null;
		try {
			Method method = null;
			if(param != null && param.length > 0){
				Class<?>[] c = new Class[param.length];
				int index = 0;
				for(Object obj : param){
					if(obj.getClass().getSimpleName().contains("String")){
						c[index] = String.class;
					} else if(obj.getClass().getSimpleName().contains("Exception") || 
							obj.getClass().getSimpleName().contains("Throwable")){
						c[index] = Throwable.class;
					}
					index++;
				}
				method = t.getClass().getMethod(methodName, c);
			} else {
				method = t.getClass().getMethod(methodName, new Class[]{ null });
			}
			result = method.invoke(t, param);
		} catch (Exception e) {
		}
		return result;
	}
    
    public static <T> Class<?>[] getParamType(T t, String methodName) throws ClassNotFoundException {
		Class<?>[] paramTypes = null;
		Method[] methods = t.getClass().getMethods();// 全部方法
		for (int i = 0; i < methods.length; i++) {
			if (methodName.equals(methods[i].getName())) {// 和传入方法名匹配
				Class<?>[] params = methods[i].getParameterTypes();
				paramTypes = new Class[params.length];
				for (int j = 0; j < params.length; j++) {
					paramTypes[j] = Class.forName(params[j].getName());
				}
				break;
			}
		}
		return paramTypes;
	}

}
